package com.isyscore.os.metadata.utils;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Lists;
import com.isyscore.os.metadata.enums.TimePeriodUnit;
import com.isyscore.os.metadata.model.dto.TimePeriodDTO;

import java.util.Date;
import java.util.List;

public class TimePeriodUtil {


    /**
     * 获取指标运算结果所属时间期的信息
     */
    public static TimePeriodDTO getTimePeriodByTimePoint(Date timePoint, TimePeriodUnit unit, Integer timePeriodNumber) {
        List<Date> dates = getTimePeriodStartAndEnd(timePoint, unit, timePeriodNumber);
        Date startTime = dates.get(0);
        Date endTime = dates.get(1);
        String timePeriodKey = null;
        switch (unit) {
            case day:
                if (timePeriodNumber == 1) {
                    timePeriodKey = DateUtil.format(timePoint, "yyyyMMdd");
                } else {
                    timePeriodKey = DateUtil.format(startTime, "yyyyMMdd") + "~" + DateUtil.format(endTime, "yyyyMMdd");
                }
                break;
            case week:
                timePeriodKey = DateUtil.format(startTime, "yyyyMMdd") + "~" + DateUtil.format(endTime, "yyyyMMdd");
                break;
            case month:
                if (timePeriodNumber == 1) {
                    timePeriodKey = DateUtil.format(timePoint, "yyyyMM");
                } else {
                    timePeriodKey = DateUtil.format(startTime, "yyyyMM") + "~" + DateUtil.format(endTime, "yyyyMM");
                }
                break;
            case year:
                if (timePeriodNumber == 1) {
                    timePeriodKey = DateUtil.format(timePoint, "yyyy");
                } else {
                    timePeriodKey = DateUtil.format(startTime, "yyyy") + "~" + DateUtil.format(endTime, "yyyy");
                }
                break;
            case quarter:
                if (timePeriodNumber == 1) {
                    timePeriodKey = getQuarterStrByDate(timePoint);
                } else {
                    timePeriodKey = getQuarterStrByDate(startTime) + "~" + getQuarterStrByDate(endTime);
                }
                break;
        }
        TimePeriodDTO periodDto = new TimePeriodDTO();
        periodDto.setKey(timePeriodKey);
        periodDto.setEndTime(endTime);
        periodDto.setStartTime(startTime);
        return periodDto;
    }

    private static Date getOffsetTimePoint(Date standardDate, TimePeriodUnit timePeriodUnit, int spanUnitNumber) {
        Date offsetTimePoint = null;
        int num = spanUnitNumber;
        if (num != 0) {
            num = -num;
        }
        switch (timePeriodUnit) {
            case day:
                offsetTimePoint = DateUtil.offsetDay(standardDate, num);
                break;
            case week:
                offsetTimePoint = DateUtil.offsetWeek(standardDate, num);
                break;
            case month:
                offsetTimePoint = DateUtil.offsetMonth(standardDate, num);
                break;
            case year:
                offsetTimePoint = DateUtil.offset(standardDate, DateField.YEAR, num);
                break;
            case quarter:
                offsetTimePoint = DateUtil.offsetMonth(standardDate, num * 3);
                break;
        }
        return offsetTimePoint;
    }

    public static List<TimePeriodDTO> getLatestPeriods(Date standardDate, TimePeriodUnit timePeriodUnit, int spanUnitNumber, int periodNumber) {
        Date point = standardDate;
        List<TimePeriodDTO> timePeriods = Lists.newArrayList();
        for (int i = 0; i < periodNumber; i++) {
            TimePeriodDTO timePeriod = TimePeriodUtil.getTimePeriodByTimePoint(point, timePeriodUnit, spanUnitNumber);
            point = getOffsetTimePoint(point, timePeriodUnit, spanUnitNumber);
            timePeriods.add(timePeriod);
        }
        return timePeriods;
    }

    private static String getQuarterStrByDate(Date date) {
        if (date == null) {
            return "";
        }
        int month = DateUtil.month(date);
        int quarter = (int) Math.floor(month / 3) + 1;
        return DateUtil.format(date, "yyyy") + "Q" + quarter;
    }

    /**
     * 根据指标设置的时间范围单位和数量，得到具体的时间范围条件
     *
     * @param timePoint        基准时间点，一般为当前时间
     * @param unit             时间范围的单位
     * @param timePeriodNumber 时间范围的数值
     * @return
     */
    private static List<Date> getTimePeriodStartAndEnd(Date timePoint, TimePeriodUnit unit, Integer timePeriodNumber) {
        DateTime startTime = null;
        DateTime endTime = null;
        int num = timePeriodNumber - 1;
        if (num != 0) {
            num = -num;
        }
        switch (unit) {
            case day:
                endTime = DateUtil.endOfDay(timePoint);
                startTime = DateUtil.beginOfDay(DateUtil.offsetDay(endTime, num));
                break;
            case week:
                endTime = DateUtil.endOfWeek(timePoint);
                startTime = DateUtil.beginOfWeek(DateUtil.offsetWeek(endTime, num));
                break;
            case month:
                endTime = DateUtil.endOfMonth(timePoint);
                startTime = DateUtil.beginOfMonth(DateUtil.offsetMonth(endTime, num));
                break;
            case year:
                endTime = DateUtil.endOfYear(timePoint);
                startTime = DateUtil.beginOfYear(DateUtil.offset(endTime, DateField.YEAR, num));
                break;
            case quarter:
                endTime = DateUtil.endOfQuarter(timePoint);
                if (timePeriodNumber == 0) {
                    startTime = DateUtil.beginOfQuarter(timePoint);
                } else {
                    //季度按3个月进行等价替换
                    startTime = DateUtil.beginOfQuarter(DateUtil.offsetMonth(endTime, num * 3));
                }
                break;
        }
        return Lists.newArrayList(startTime, endTime);
    }


}
